
#include <bdlib/src/String.h>
#include <bdlib/src/Stream.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <algorithm>

int skipline (const char *line, int *skip) {
  static int multi = 0;
  if ((!strncmp(line, "//", 2))) {
    (*skip)++;
  } else if ( (strstr(line, "/*")) && (strstr(line, "*/")) ) {
    multi = 0;
    (*skip)++;
  } else if ( (strstr(line, "/*")) ) {
    (*skip)++;
    multi = 1;
  } else if ( (strstr(line, "*/")) ) {
    multi = 0;
  } else {
    if (!multi) (*skip) = 0;
  }
  return (*skip);
}

int parse_res(const bd::String& inFile, const bd::String& outFile, const bd::String& outsFile) {
  bd::Stream in, out, outs;
  bd::String buffer, cmd, buf, lower_resps;

  int skip = 0, total_responses = 0;

  in.loadFile(inFile);
  printf("Parsing res file '%s'", inFile.c_str());

  out << bd::String::printf( "/* DO NOT EDIT THIS FILE. */\n\
#ifndef _RESPONSE_H\n\
#define _RESPONSE_H\n\
\n\
typedef unsigned int response_t;\n\n\
enum {\n");

  outs << bd::String::printf("/* DO NOT EDIT THIS FILE. */\n\
#ifndef _RESPONSES_H\n\
#define _RESPONSES_H\n\
\n\
typedef const char * res_t;\n\n");

  while (in.tell() < in.length()) {
    buffer = in.getline().chomp();
    if ((skipline(buffer.c_str(), &skip))) continue;
    if (buffer[0] == ':') { /* New cmd */
      if (cmd.length()) {		/* CLOSE LAST RES */
        out << ",\n";	/* for enum */
        outs << "\tNULL\n};\n\n";
        cmd.clear();
      }

      cmd = buffer(1);
      if (cmd != "end") {		/* NEXT RES */
        ++total_responses;
        printf(".");

        bd::String cmdUpper(cmd);
        std::transform(cmdUpper.begin(), cmdUpper.end(), cmdUpper.mdata(), (int(*)(int)) toupper);
        out << bd::String::printf("\tRES_%s", cmdUpper.c_str());
        if (total_responses == 1)
          out << " = 1";
        outs << bd::String::printf("static res_t res_%s[] = {\n", cmd.c_str());
        lower_resps += bd::String::printf(",\n\tres_%s", cmd.c_str());
      } else {			/* END */
        out << bd::String::printf("\tRES_END\n};\n\n#define RES_TYPES %d\n", total_responses);
        out << bd::String::printf("const char *response(response_t);\nvoid init_responses();\nconst char *r_banned(struct chanset_t* chan);\n\n#endif /* !_RESPONSE_H */\n");
        outs << bd::String::printf("static res_t *res[] = {\n\tNULL%s\n};\n#endif /* !_RESPONSES_H */\n", lower_resps.c_str());
      }
    } else {				/* NEXT RES TEXT */
      ++buffer;
      outs << bd::String::printf("\t\"%s\",\n", buffer.c_str());
    }
  }

  if (out.writeFile(outFile)) {
    fprintf(stderr, "Failure writing %s\n", outFile.c_str());
    return 1;
  }

  if (outs.writeFile(outsFile)) {
    fprintf(stderr, "Failure writing %s\n", outsFile.c_str());
    return 1;
  }

  printf(" Success\n");

  return 0;
}

int main(int argc, char **argv) {
  if (argc < 3) return 1;

  bd::String in(argv[1]), out, outs;

  out = bd::String::printf("%s/response.h%s", argv[2], argc == 4 ? "~" : "");
  outs = bd::String::printf("%s/responses.h%s", argv[2], argc == 4 ? "~" : "");
  return parse_res(in, out, outs);
}
